// 5-2 多线程处理-向线程传递参数
/**
 * C++ 多线程
 * 多线程是多任务处理的一种特殊形式，多任务处理允许让电脑同时运行两个或两个以上的程序。一般情况下，两种类型的多任务处理：基于进程和基于线程。

      **基于进程**的多任务处理是**程序的并发执行**。
      **基于线程****的多任务处理是**同一程序的片段的并发执行**。

 * 多线程程序包含可以同时运行的两个或多个部分。这样的程序中的每个部分称为一个线程，每个线程定义了一个单独的执行路径。

 * 本教程假设您使用的是 Linux 操作系统，我们要使用 POSIX 编写多线程 C++ 程序。POSIX Threads 或 Pthreads 提供的 API 可在多种类 Unix POSIX 系统上可用，比如 FreeBSD、NetBSD、GNU/Linux、Mac OS X 和 Solaris。

 *
 *
 * 创建线程
 * 下面的程序，我们可以用它来创建一个 POSIX 线程：

        #include <pthread.h>
        pthread_create (thread, attr, start_routine, arg) 

 * 在这里，pthread_create 创建一个新的线程，并让它可执行。下面是关于参数的说明：

      参数	        描述
      thread	      指向线程标识符指针。
      attr	        一个不透明的属性对象，可以被用来设置线程属性。您可以指定线程属性对象，也可以使用默认值 NULL。
      start_routine	线程运行函数起始地址，一旦线程被创建就会执行。
      arg	          运行函数的参数。它必须通过把**引用作为指针强制转换为 void 类型**进行传递。如果没有传递参数，则使用 NULL。
 
 * 创建线程成功时，函数返回 0，若返回值不为 0 则说明创建线程失败。
 *
 * 
 * 终止线程
 * 使用下面的程序，我们可以用它来终止一个 POSIX 线程：

        #include <pthread.h>
        pthread_exit (status) 

 * 在这里，pthread_exit 用于显式地退出一个线程。通常情况下，pthread_exit() 函数是在线程完成工作后无需继续存在时被调用。

 * 如果 main() 是在它所创建的线程之前结束，并通过 pthread_exit() 退出，那么其他线程将继续执行。否则，它们将在 main() 结束时自动被终止。
 *
 * --------------------------------
 * 向线程传递参数
 * 这个实例演示了如何通过结构传递多个参数。您可以在线程回调中传递任意的数据类型，因为它指向 void，如下面的实例（实例1）所示：
*/

#include <iostream>
#define __mark 1

/**
 * #1 实例1
 * 编译 g++ 5_2.cpp -lpthread -o ./build/5_1.o
 * 执行程序 5_2.o
*/
#if 1 == __mark
#include <pthread.h>
#include <string.h>
#include <windows.h>
#define CONCAT(X)(#X)
typedef struct thread_data
{
  int id;
  char msg[50];
  void func()
  {
    std::cout << "test" << std::endl;
  }
} thread_data;

void *thread_func(void *argv)
{
  thread_data *d = (thread_data *)argv;
  std::cout << "thread id : " << d->id;
  // char * 数据cout打印有问题，转换为(非 char*),不过我这个是char []
  std::cout << " thread msg : " << d->msg << std::endl;
  d->func();

  pthread_exit(NULL);
  return 0;
}
int main(void)
{
  const int size = 5;
  pthread_t threads[size];
  thread_data argvs[size];
  for (int i = 0; i < size; i++)
  {
    
    // thread_data d;
    // d.id = i + 1;
    // strcpy(d.msg, "msg" + (i + 1));// 错误
    // strcpy(d.msg, "This is a msg!");

    argvs[i].id = i + 1;
    strcpy(argvs[i].msg, "This is a msg!");

    // (void *)&d
    // (void *)&argvs[i]
    int res = pthread_create(&threads[i], NULL, thread_func, (void *)&argvs[i]);
    if (res != 0)
    {
      std::cerr << "create thread " << i << "error!error code :" << res << std::endl;
      exit(-1);
    }
    Sleep(500);
  }
  pthread_exit(NULL);

  printf("---------------------end---------------\n");
  return 0;
}
/**
 * #2 实例二
*/
#elif 2 == __mark
int main(void)
{

  printf("---------------------end---------------\n");
  return 0;
}
#endif
